﻿using System;
using System.Linq;
using System.Configuration.Provider;
using System.Collections.Specialized;
using System.Threading;
using System.IO;
using Microsoft.Practices.EnterpriseLibrary.Data.Sql;
 

namespace FileMonitor.Configuration.Prototype.FileMonitorProcess
{
    public enum SplitFlag
    {
        CHAR,
        LENGTH
    }

    public abstract class FileMonitorProcessBase:ProviderBase,IDisposable
    {
        protected NameValueCollection AllConfig;
    //    private Thread workProcessThread;
      //  private bool disposed = false;
        private MonitorProcessInfo processInfo;
        private System.IO.FileSystemWatcher fileWatcher;
        protected Microsoft.Practices.EnterpriseLibrary.Data.Sql.SqlDatabase exchangeDB;
        public string statusMsg = "";
        System.Threading.Timer timer;
        protected SplitFlag splitFlag = SplitFlag.CHAR;

        public MonitorProcessInfo ProcessInfo
        {
            get
            {
                return this.processInfo;
            }
        }

        private bool moving_Mutex = false;
        private object objMutex = new object();
      

        
        public override string Description
        {
            get
            {
                return base.Description;
            }
        }

        public override string Name
        {
            get
            {
                return base.Name;
            }
        }

        public override void Initialize(string name, NameValueCollection config)
        {
            base.Initialize(name, config);
            if (config["MonitorPath"] == null)
            {
                throw new ArgumentException("Must_Set_MonitorPath");
            }
            if (!string.IsNullOrEmpty(config["SplitArr"]))
            {
                splitFlag = SplitFlag.LENGTH;
            }
            exchangeDB = new SqlDatabase(System.Configuration.ConfigurationManager.ConnectionStrings["DefaultExchangeDB"].ConnectionString);
            AllConfig = config;
        }

        public void Dispose()
        {
            this.fileWatcher = null;
            this.timer.Dispose();
        }

      
        internal void Start()
        {
            try
            {
              if (this.fileWatcher == null)
                {
                    fileWatcher = new System.IO.FileSystemWatcher();
                    string monitorPath = this.AllConfig["MonitorPath"] + "\\temp";

                    if (!System.IO.Directory.Exists(monitorPath))
                    {
                        System.IO.Directory.CreateDirectory(monitorPath);
                    }
                    fileWatcher.Path = monitorPath;//this.AllConfig["MonitorPath"];
                    if (string.IsNullOrEmpty(this.AllConfig["Filter"]))
                    {
                        fileWatcher.Filter = "*.*";
                    }
                    else
                    {
                        fileWatcher.Filter = this.AllConfig["Filter"];
                    }

                }
                if (!fileWatcher.EnableRaisingEvents)
                {
                    fileWatcher.EnableRaisingEvents = true;
                }
                fileWatcher.InternalBufferSize = 16384;
                fileWatcher.Created += new System.IO.FileSystemEventHandler(fileWatcher_Created);
                fileWatcher.Changed += new System.IO.FileSystemEventHandler(fileWatcher_Changed);
                fileWatcher.Deleted += new System.IO.FileSystemEventHandler(fileWatcher_Deleted);

                if (this.processInfo == null)
                {
                    this.processInfo = new MonitorProcessInfo(this.Name, this.Description);
                    this.processInfo.State = ProcessState.Starting;
                    this.processInfo.MonitorPath = this.AllConfig["MonitorPath"];
                }
                if (this.timer == null)
                {
                    timer = new Timer(new TimerCallback(MoveFile), this,5,2000);
                }
            }
            catch (Exception ex)
            { }
        }

        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            
        }

        private void MoveFile(object obj)
        {
            try
            {
                if (!this.moving_Mutex)
                {
                    lock (this.objMutex)
                    {
                        if (!this.moving_Mutex)
                        {
                            this.moving_Mutex = true;
                            string path = (obj as FileMonitorProcessBase).AllConfig["MonitorPath"];
                            string[] files = System.IO.Directory.GetFiles(path);
                            foreach (string fileName in files)
                            {
                                if (fileName.EndsWith(".zip", true, null) || fileName.EndsWith(".rar", true, null) || fileName.EndsWith(".7z", true, null))
                                {
                                    FileUtility.ZIP.UnZip unZip = new FileUtility.ZIP.UnZip();
                                    unZip.UnZipFile(fileName, path + "\\temp\\", true);
                                    System.Threading.Thread.Sleep(1000);
                                    System.IO.File.Move(fileName, path + "\\temp\\" + fileName.Substring(fileName.LastIndexOf("\\") + 1));
                                }
                                else
                                {
                                    if (IsMonitorFile(fileName))
                                    {
                                       System.IO.File.Move(fileName, path + "\\temp\\" + fileName.Substring(fileName.LastIndexOf("\\") + 1));
                                    }

                                    string actualFileName = fileName.Substring(fileName.LastIndexOf("\\") + 1);
                                    if (!this.processInfo.FileInfos.ContainsKey(actualFileName))
                                    {
                                        FileInfo fi = new FileInfo(actualFileName);
                                        fi.State = FileState.ToBeProcess;
                                        fi.CuurentFullPath = path + "\\temp\\" + actualFileName;
                                        fi.InitialFullPath = path + actualFileName;
                                        this.processInfo.FileInfos.Add(actualFileName, fi);
                                    }
                                    //else
                                    //{
                                    //    if (!fileName.EndsWith(".Ignore", true, null))
                                    //    {
                                    //        string ignorePath = fileName + ".Ignore";
                                    //        if (System.IO.File.Exists(ignorePath))
                                    //        {
                                    //            System.IO.File.Delete(ignorePath);
                                    //        }
                                    //        System.IO.File.Move(fileName, fileName + ".Ignore");
                                    //    }
                                    //}
                                }
                            }
                            this.moving_Mutex = false;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
              //  Log.Log.LogMessage(System.DateTime.Now.ToString()+"-------"+ex.Message, this.AllConfig["LogPath"]);
            }
        }


        void fileWatcher_Deleted(object sender, System.IO.FileSystemEventArgs e)
        {
            this.ProcessDeleted(e);
        }

        void fileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e)
        {
            this.ProcessChanged(e);
        }

        void fileWatcher_Created(object sender, System.IO.FileSystemEventArgs e)
        {
            int waitTime = 1;
            Int32.TryParse(this.AllConfig["WaitTime"], out waitTime);
            if (waitTime == 0)
            {
                waitTime = 1;
            }
            System.Threading.Thread.Sleep(waitTime * 1000);
            try
            {

                if (System.IO.File.Exists(e.FullPath))
                {
                    this.processInfo.FileInfos[e.Name].State = FileState.Processing;
                    this.ProcessCreated(e);
                    string backupPath = this.AllConfig["BackUpPath"] + "\\" + e.Name;
                    if (System.IO.File.Exists(backupPath))
                    {
                        System.IO.File.Delete(backupPath);
                    }
                    System.IO.File.Move(e.FullPath, this.AllConfig["BackUpPath"] + "\\" + e.Name);
                    this.processInfo.FileInfos[e.Name].State = FileState.Processed;
                    this.processInfo.FileInfos[e.Name].ProcessedDate =DateTime.Now;

                    this.processInfo.FileInfos[e.Name].CuurentFullPath = this.AllConfig["BackUpPath"] + "\\" + e.Name;
                }
            }
            catch (Exception ex)
            {
                string errorPath = e.FullPath + ".Error";
                if (System.IO.File.Exists(errorPath))
                {
                    System.IO.File.Delete(errorPath);
                }

                System.IO.File.Move(e.FullPath, e.FullPath + ".Error");
                this.processInfo.FileInfos[e.Name].State = FileState.Error;
                this.processInfo.FileInfos[e.Name].CuurentFullPath = e.FullPath + ".Error";

                // Log.Log.LogMessage(System.DateTime.Now.ToString() + "-------" +e.Name+"---------"+ex.Message, this.AllConfig["LogPath"]);
            }
        }

        internal void Stop()
        {
            this.processInfo.State = ProcessState.Pause;
            this.Dispose();

        }

        
        public abstract void ProcessCreated(FileSystemEventArgs e);
        public abstract void ProcessChanged(FileSystemEventArgs e);
        public abstract void ProcessDeleted(FileSystemEventArgs e);

        #region Utility Methods
        private bool IsMonitorFile(string fileName)
        {
            string extName="*"+fileName.Substring(fileName.LastIndexOf("."));
            string[] filterArr = this.AllConfig["Filter"].Split(",".ToCharArray());
            for (int i = 0; i < filterArr.Length; i++)
            {
                filterArr[i] = filterArr[i].ToUpper();
            }
            if (filterArr.Contains("*.*"))
                    return true;
            return filterArr.Contains(extName.ToUpper());
        }

        #endregion

    }
}
